/**
 * services/qiniu
 */

import axios from 'axios';
import lodash from 'lodash';
import Promise from 'bluebird';
import TokenModel from '../models/token';

import TTXS from '../common/ttxs';

const rAbsURL = /^(\/|https?:\/\/)/i;
const baseURL = TTXS.assetsBaseURL || '/assets/';
const rBaseURL = new RegExp('^(?:https?:)?' + lodash.escapeRegExp(baseURL.replace(/^https?:/i, '')));

const urlEncode = encodeURIComponent;

export default {
    // url
    baseURL: baseURL,
    normalizeUrl(key, params) {
        let newURL = String(key).trim().replace(rBaseURL, '');

        if(!newURL || rAbsURL.test(newURL)) {
            return key;
        }

        // prefix
        newURL = baseURL + newURL;

        // params
        if(params) {
            if(typeof params === 'object') {
                params = Object.keys(params).map(k => {
                    return urlEncode(k) + '=' + urlEncode(params[k]);
                })
                .join('&');
            }

            newURL += newURL.indexOf('?') < 0 ? '?' : '&';
            newURL += params;
        }

        return newURL;
    },

    uid: 0,
    // key
    getKey(file, key = '') {
        // auto prefix
        if(!key) {
            const uriArr = location.pathname.split('/');

            key = [
                TTXS.assetsPrefix + TTXS.userId,
                ...uriArr.slice(1, 3)
            ]
            .join('/');

            key = key.replace(/\/*$/, '/');
        }

        // fill filename
        // 如果以 / 结尾，则自动补全文件名
        if(key.slice(-1) === '/') {
            let now = new Date();

            let filename = now.getFullYear();
            filename += ('00' + now.getMonth()).slice(-2);
            filename += ('00' + now.getDate()).slice(-2);
            filename += '-';
            filename += ('00' + now.getHours()).slice(-2);
            filename += ('00' + now.getMinutes()).slice(-2);
            filename += ('00' + now.getSeconds()).slice(-2);

            filename += '-';
            filename += (++this.uid);
            filename += '.' + this.getExtByFile(file);

            key += filename;
        }

        return key;
    },
    extsMap: {
        jpeg: 'jpg'
    },
    getExtByFile(file) {
        let name = file.name;
        if(!name) {
            name = file.type.split('/')[1];
        }

        let ext = name.slice(name.lastIndexOf('.') + 1);
        return this.extsMap[ext] || ext || 'unknow';
    },

    // token
    tokenTimeout: 5 * 60 * 1000,
    lastToken: {
        type: 'qiniu',
        timestamp: 0,
        token: ''
    },
    tokenPromise: null,
    getToken(key) {
        const lastToken = this.lastToken;
        const elapsed = Date.now() - lastToken.timestamp;

        // check timeout
        if(elapsed <= this.tokenTimeout) {
            return Promise.resolve(lastToken.token);
        }

        // check cache
        if(!this.tokenPromise) {
            this.tokenPromise = TokenModel.save({
                type: lastToken.type,
                key: key
            })
            .$promise
            .then(res => {
                lastToken.timestamp = Date.now();
                lastToken.token = res.token;

                return lastToken.token;
            })
            .finally(() => {
                this.tokenPromise = null;
            });
        }

        return this.tokenPromise;
    },

    // upload
    uploadTimeout: 5 * 60 * 1000,
    imageUploadURL: '//image-uploader.dancf.com',
    uploadURL: '//up.qbox.me',
    upload(file, key, options = {}) {
        const {
            filename,
            action, data, timeout,
            headers, withCredentials,
            onProgress
        } = options;

        return Promise.try(() => {
            if(!file || !file.size) {
                throw new Error('file 参数错误');
            }

            // Auto fill key
            if(!key) {
                key = this.getKey(file);
            }

            // 不允许传文件到根目录
            if(!key || key.indexOf('/') < 0) {
                throw new Error('key 参数错误');
            }
        })
        .then(() => {
            return Promise.props({
                ...data,
                token: this.getToken(key),
                key
            });
        })
        .then(data => {
            const formData = new FormData();

            Object.keys(data).map(k => {
                formData.append(k, data[k]);
            });

            formData.append(filename || 'file', file);

            let actionUrl = action;
            if(!actionUrl) {
                const rImage = /\.(?:png|jpe?g|gif|svg)$/i;

                actionUrl = rImage.test(data.key)
                    ? this.imageUploadURL
                    : this.uploadURL;
            }

            return axios.post(actionUrl, formData, {
                headers,
                withCredentials,
                timeout: timeout || this.uploadTimeout,

                onUploadProgress(e) {
                    e.percent = 100 * e.loaded / e.total;

                    if(onProgress) {
                        onProgress(e);
                    }
                }
            });
        })
        .then(({data}) => {
            // Fill url
            if(!data.url) {
                data.url = this.baseURL + data.key;
            }

            return data;
        });
    }
};
